/*******************************************************************************
+
+  LEDA 6.3  
+
+
+  windows.c
+
+
+  Copyright (c) 1995-2010
+  by Algorithmic Solutions Software GmbH
+  All rights reserved.
+ 
*******************************************************************************/

#include "StdAfx.h"
#include "MatrixUtil.h"
#include <LEDA/graphics/window.h>
#include <LEDA/graphics/bitmaps/button32.h>
#include <LEDA/core/string.h>
#include <LEDA/graphics/geowin.h>
#include <LEDA/geo/rectangle.h>
#include <LEDA/geo/circle.h>
#include <LEDA/geo/rat_rectangle.h>
#include <LEDA/numbers/integer.h>
#include <cstdlib> 
using namespace leda;
#if defined(LEDA_STD_IO_HEADERS)
using std::cout;
using std::cin;
using std::endl;
#endif
int type = 0;
window w1(1024,250,"MATRIX CHAIN ORDER");
window m(500,300,"MATRIX M");
window s(500,300,"MATRIX S");
window r(500,300,"MATRIX RESULT");
string matrixinput="";

list<string> CML;
list<string> CML1;
string quantityDefault = "3";
string dimensionDefault = "1..5";
string sequenceOfDimensions = "";
string optimalParenthesization = "";
string normalCost = "";
string optimizeCost = "";

integer dimension_min;
integer dimension_max;
MatrixUtil * aMatrixUtil;
int my_event_handler(window* wp, int e, int val, double x, double y, 
                                                            unsigned long t)
{ 
  if (e == button_press_event || e == button_release_event)
     cout << e << " " << val << " " << x << " " << y << " " << t << endl;

  return no_event; // read_mouse will not terminate
}
/*
void draw_matrix_cell(window& m,double x,double y){
	int n = 5;
	 list<point>  frame;

	frame.append(point(x-5,y));
	frame.append(point(x,y+5));
	frame.append(point(x+5,y));
	frame.append(point(x,y-5));
	m.draw_filled_polygon(frame,red);
	m.set_mode(xor_mode);
	m.draw_text(x-3,y+2,"hello",black);
}
void drawMarix(window& m,double x,double y)
{
	for(int i=10;i<20;i=i+10)
	{
		for(int j=10;j<100;j=j+10)
			draw_matrix_cell(m,j,i);
	}
	for(int i=15;i<20;i=i+10)
	{
		for(int j=15;j<90;j=j+10)
			draw_matrix_cell(m,j,i);
	}
	for(int i=20;i<25;i=i+10)
	{
		for(int j=20;j<85;j=j+10)
			draw_matrix_cell(m,j,i);
	}
	for(int i=25;i<30;i=i+10)
	{
		for(int j=25;j<80;j=j+10)
			draw_matrix_cell(m,j,i);
	}
	for(int i=30;i<35;i=i+10)
	{
		for(int j=30;j<75;j=j+10)
			draw_matrix_cell(m,j,i);
	}
	for(int i=35;i<40;i=i+10)
	{
		for(int j=35;j<70;j=j+10)
			draw_matrix_cell(m,j,i);
	}
	for(int i=40;i<45;i=i+10)
	{
		for(int j=40;j<65;j=j+10)
			draw_matrix_cell(m,j,i);
	}
	for(int i=45;i<50;i=i+10)
	{
		for(int j=45;j<60;j=j+10)
			draw_matrix_cell(m,j,i);
	}
	for(int i=50;i<55;i=i+10)
	{
		for(int j=50;j<55;j=j+10)
			draw_matrix_cell(m,j,i);
	}
}
*/

void draw_matrix_cell(window& m,double x,double y,string str){
	int n = 5;
	 list<point>  frame;

	frame.append(point(x-5,y));
	frame.append(point(x,y+5));
	frame.append(point(x+5,y));
	frame.append(point(x,y-5));
	m.draw_filled_polygon(frame,grey1);
	m.set_mode(xor_mode);
	m.draw_text(x-1,y+2,str,black);
}
void drawMarix_M(window& m,double x,double y)
{
	int iDelta = 0;
	int h = 1;
	for(int k = 1;k<aMatrixUtil->iSIZE+1;k++)
	{
		for(int i=10+iDelta;i<15+iDelta;i=i+10)
		{
			h = 1;
			int k1 = k;
			for(int j=10+iDelta;j<10*aMatrixUtil->iSIZE-iDelta;j=j+10)
			{
				int iRes = aMatrixUtil->M[h][k1];
				integer iInt(iRes);
				draw_matrix_cell(m,j,i,iInt.to_string());
				k1 += 1;
				h += 1;
				if(k == 1) // print alpha
				{
					int iPos = j/10 - 1;
					m.draw_text(j-3,i-5,aMatrixUtil->alpha.sub(iPos,iPos),black);
					//m.draw_text(j-2,i-5,aMatrixUtil->alpha.sub(iPos,iPos),black);
				}
			}
		}
		iDelta += 5;
	}
}

void drawMarix_S(window& m,double x,double y)
{
	int iDelta = 0;
	int h = 1;
	for(int k = 2;k<aMatrixUtil->iSIZE;k++)
	{
		for(int i=10+iDelta;i<15+iDelta;i=i+10)
		{
			h = 1;
			int k1 = k;
			for(int j=10+iDelta;j<10*(aMatrixUtil->iSIZE-1)-iDelta;j=j+10)
			{
				int iRes = aMatrixUtil->S[h][k1];
				integer iInt(iRes);
				draw_matrix_cell(m,j,i,iInt.to_string());
				k1 += 1;
				h += 1;
			}
		}
		iDelta += 5;
	}
}
void drawResultMatrix(window& m,double x,double y)
{
	int iDelta = 0;
	int iRow = aMatrixUtil->matrix_result.dim1();
	int iCol = aMatrixUtil->matrix_result.dim2();
	for(int i = iDelta;i<iDelta+10*(iRow);i = i+10)
	{
		integer_vector v = aMatrixUtil->matrix_result.row(iRow-1 - ((i-iDelta)/10));
		for(int j = iDelta;j<iDelta+10*(iCol);j = j+10){
			integer iInt = v[((j-iDelta)/10)];
			m.draw_rectangle(j,i,j+10,i+10);
			m.draw_text((2*j+3)/2,(2*i+10)/2,iInt.to_string(),black);
		}
	}
}
void redrawM(window* wp)
{
  wp->clear();
  drawMarix_M(m,50,50);
}
void redrawR(window* wp)
{
  wp->clear();
  drawResultMatrix(r,0,0);
}
void redrawS(window* wp)
{
  wp->clear();
  drawMarix_S(s,50,50);
}
void scrollM(window* wp,double x1,double y1,double x2,double y2)
{
  wp->clear();
  drawMarix_S(s,50,50);
}
void handleError(string error)
{
	panel P("Error");

    //P.load_button_font("lucidasans-12");

    string text = error;
  
    P.text_item(text);
    P.text_item("");
    P.button("quit");
    P.display();

	P.read_mouse();
}
string generateRandommatrix(integer quantity,integer dimension_min,integer dimension_max)
{
	string result="";
	integer temp = 0;
	for(integer i=0;i<quantity;i++)
	{
		
		integer d1 = ((integer)rand()+2)%dimension_max;
		integer d2 = ((integer)rand()+2)%dimension_max;
		if (d1 == 0)
			d1 = 1;
		if(d2 ==0)
			d2 = 1;
		if(i == 0){
			temp = d2;
			string first = "matrix("+d1.to_string()+","+d2.to_string()+")";
			result += first;
		}
		else
		{
			d1 = temp;
			string inter = "*matrix("+d1.to_string()+","+d2.to_string()+")";
			result += inter;
			temp = d2;
		}
	}
	return result;
}
void parseDimension(string input)
{
	string min,max;
	int count =0;
	for(int i =0;i<input.length();i++)
	{
		if(input[i] != '.'){
			if(count != 2)
				min+=input[i];
			else
				max +=input[i];
		}
		else
		{
			count++;
		}
	}
	dimension_min = integer(min);
	dimension_max = integer(max);
}
class style_action : public window_handler {
public:
  void operator()() 
  { 
	  int n =get_int(); 
	  if(n == 50)
	  {
		if (type == 3 || type == 2)
		{
			char strInput[1000] ;//= "matrix(1,4)*matrix(4,3)*matrix(3,2)*matrix(2,2)*matrix(2,1)*matrix(1,2)*matrix(2,1)";
			char *pointer = (char*)matrixinput.c_str();
			strcpy(strInput,pointer);
			if(aMatrixUtil != NULL)
				delete aMatrixUtil;
			aMatrixUtil = new MatrixUtil(strInput);	
			switch(aMatrixUtil->iErrorCode)
			{
			case -1:
				handleError("Input string is wrong format");
				//cout<<"Input string is wrong format";
				return;
			case -2:
				handleError("The size is not fitable");
				//cout<<"The size is not fitable";
				return;
			case -3:
				handleError("The Quantity is over than 1000");
				//cout<<"The Quantity is over than 1000";
				return;
			}

			aMatrixUtil->MatrixChainOrder(aMatrixUtil->iSIZE);
			aMatrixUtil->Print_M1();
			string result = aMatrixUtil->PrintParenthese(0,aMatrixUtil->iSIZE-2,1,aMatrixUtil->iSIZE-1);
			string str = aMatrixUtil->retStringFromMatrixP();
		
			cout<<"-----------------------------------------------------------"<<str<<endl;
			cout<<"Optimize parenthese ="<<result<<endl;
			cout<<"-----------------------------------------------------------"<<endl;
			int normal = aMatrixUtil->NormalCost();
			cout<<"Normal cost = "<<normal<<endl;
			cout<<"-----------------------------------------------------------"<<endl;
			int optimize = aMatrixUtil->OptimizeCost();
			cout<<"Optimize cost = "<<optimize<<endl;
			optimalParenthesization = result; 
			normalCost = integer(normal).to_string();
			optimizeCost = integer(optimize).to_string();
			sequenceOfDimensions = aMatrixUtil->retStringFromMatrixP();
			w1.redraw_panel(w1.get_item("Optimal Parenthesization"));
			w1.redraw_panel(w1.get_item("Left To Right Scalar Multiplication"));
			w1.redraw_panel(w1.get_item("Optimized Scalar Multiplication"));
			w1.redraw_panel(w1.get_item("Sequence Of Dimensions"));
		}
		else if(type == 1)
		{			
			string strInput(matrixinput);
			if(aMatrixUtil != NULL)
				delete aMatrixUtil;
			aMatrixUtil = new MatrixUtil();	
			aMatrixUtil->processCommand(strInput);
			integer_matrix  matrix_result = aMatrixUtil->matrix_result;
			char strMessage[200];
			integer iSeq(aMatrixUtil->iSequenceNumber);
			string strSeq = iSeq.to_string();
			switch(aMatrixUtil->iErrorCode)
			{
			case aMatrixUtil->TheSizeNotFitable:
				strcpy(strMessage,"The size is not fitable at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"The size is not fitable at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->InputStringIsNull:
				strcpy(strMessage,"Input string is null");
				handleError(strMessage);
				return;
			case aMatrixUtil->MissingKeywordMatrixForEntry:
				strcpy(strMessage,"MissingKeywordMatrixForEntry at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"MissingKeywordMatrixForEntry at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->MissingOpeningParenthesisForMatrix:
				strcpy(strMessage,"MissingOpeningParenthesisForMatrix at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"MissingOpeningParenthesisForMatrix at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->MissingClosingParenthesisForMatrix:
				strcpy(strMessage,"MissingClosingParenthesisForMatrix at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"MissingClosingParenthesisForMatrix at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->MissingTheFirstComma:
				strcpy(strMessage,"MissingTheFirstComma at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"MissingTheFirstComma at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->RowCannotBe0ForMatrix:
				strcpy(strMessage,"RowCannotBe0ForMatrix at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"RowCannotBe0ForMatrix at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->MissingSecondComma:
				strcpy(strMessage,"MissingSecondComma at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"MissingSecondComma at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->ColumnCannotBe0ForMatrix:
				strcpy(strMessage,"ColumnCannotBe0ForMatrix at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"ColumnCannotBe0ForMatrix at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->MissingOpeningBracketForMatrix:
				strcpy(strMessage,"MissingOpeningBracketForMatrix at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"MissingOpeningBracketForMatrix at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->MissingClosingBracketForMatrix:
				strcpy(strMessage,"MissingClosingBracketForMatrix at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"MissingClosingBracketForMatrix at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->TooFewEntriesForMatrix:
				strcpy(strMessage,"TooFewEntriesForMatrix at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"TooFewEntriesForMatrix at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->SyntaxErrorInExpressionAfterMatrix:
				strcpy(strMessage,"SyntaxErrorInExpressionAfterMatrix at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"SyntaxErrorInExpressionAfterMatrix at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->MissingAtTheRow:
				strcpy(strMessage,"MissingAtTheRow at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"MissingAtTheRow at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->MissingAtTheCol:
				strcpy(strMessage,"MissingAtTheCol at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"MissingAtTheCol at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			case aMatrixUtil->TheNumberInMatrixError:
				strcpy(strMessage,"TheNumberInMatrixError at sequence: ");
				strcat(strMessage,strSeq.cstring());
				handleError(strMessage);
				cout<<"TheNumberInMatrixError at sequence: "<<aMatrixUtil->iSequenceNumber<<endl;
				return;
			}
			string result = aMatrixUtil->PrintParenthese(0,aMatrixUtil->iSIZE-2,1,aMatrixUtil->iSIZE-1);
			int normal = aMatrixUtil->NormalCost();
			int optimize = aMatrixUtil->OptimizeCost();
			optimalParenthesization = result; 
			normalCost = integer(normal).to_string();
			optimizeCost = integer(optimize).to_string();
			sequenceOfDimensions = aMatrixUtil->retStringFromMatrixP();
			w1.redraw_panel(w1.get_item("Optimal Parenthesization"));
			w1.redraw_panel(w1.get_item("Left To Right Scalar Multiplication"));
			w1.redraw_panel(w1.get_item("Optimized Scalar Multiplication"));
			w1.redraw_panel(w1.get_item("Sequence Of Dimensions"));
		}
		else
			return;
		//window m(500,300,"MATRIX M");
		m.display(window::min,window::center);
		drawMarix_M(m,50,50);
		m.set_redraw(redrawM);
		
		//m.scroll_window(point(0,0),scrollM);
		//window s(500,300,"MATRIX S");
		s.display(window::max,window::center);
		s.set_redraw(redrawS);
		drawMarix_S(s,50,50);
		if(type == 1){
			r.display(window::center,window::min);
			//r.open();
			r.set_redraw(redrawR);
			drawResultMatrix(r,0,0);
		}
		 window* w;
		 double  x,y;
		 point   p;

	   while(read_mouse(w,x,y) != MOUSE_BUTTON(3))  
	   { 
		 if (w == &m) // draw points
		 {
			 put_back_event();
			  m >> p;
			 continue;
		  }
	
	   }
	}
  }
};


class choice_action : public window_handler {
public:
  void operator()() 
  { 
	  int n =get_int(); 
	  if(n==0){
		  type = 1;
		  w1.disable_item(w1.get_item("Quantity"));
		  w1.disable_item(w1.get_item("Dimension"));
		  matrixinput = "matrix(3,3,[-362,-385,-408,570,675,780,-362,-301,-240])*matrix(3,1,[1,2,3])*matrix(1,4,,[4,5,6,7])";
		  w1.redraw_panel(w1.get_item("Matrix Input"));
		  w1.enable_item(w1.get_item("Compute"));
		  w1.enable_item(w1.get_item("Reset"));
	  }
	  else if (n==1){
		  type = 2;
		  w1.disable_item(w1.get_item("Quantity"));
		  w1.disable_item(w1.get_item("Dimension"));
		  matrixinput = "matrix(1,2)*matrix(2,3)*matrix(3,4)";
		  w1.redraw_panel(w1.get_item("Matrix Input"));
		  w1.enable_item(w1.get_item("Compute"));
		  w1.enable_item(w1.get_item("Reset"));
	  }
	  else if (n==2){
		  type = 3;
		  w1.enable_item(w1.get_item("Quantity"));
		  w1.enable_item(w1.get_item("Dimension"));
		  matrixinput = "matrix(1,2)*matrix(2,3)*matrix(3,4)*matrix(4,5)";
		  w1.redraw_panel(w1.get_item("Matrix Input"));
		  w1.enable_item(w1.get_item("Compute"));
		  w1.enable_item(w1.get_item("Reset"));
	  }
  }
};
class quantity_action : public window_handler {
public:
  void operator()() 
  { 
	  parseDimension(dimensionDefault);
	  matrixinput = generateRandommatrix(integer(quantityDefault),dimension_min,dimension_max);
	  w1.redraw_panel(w1.get_item("Matrix Input"));

  }
};
class dimesion_action : public window_handler {
public:
  void operator()() 
  { 
	 parseDimension(dimensionDefault);
	 matrixinput = generateRandommatrix(integer(quantityDefault),dimension_min,dimension_max);
	 w1.redraw_panel(w1.get_item("Matrix Input"));

  }
};
class reset_action : public window_handler {
public:
  void operator()() 
  { 
	  m.close();
	  s.close();
	  if(type == 1)
		  r.close();

  }
};

int main()
{
	bool B=true;
	
	string s1="0";

	string s="";
	style_action   but_action;
	choice_action   choice_handler;
	quantity_action quantity_handler;
	dimesion_action dimesion_handler;
	reset_action reset_handler;
    CML.append("1"); CML.append("2");
    CML.append("3"); CML.append("4");CML.append("5");CML.append("6");CML.append("7");CML.append("8");CML.append("9");
	CML.append("10");CML.append("11");CML.append("12");CML.append("13");CML.append("14");CML.append("15");CML.append("16");
	CML.append("17");CML.append("18");CML.append("19");CML.append("20");CML.append("21");CML.append("22");CML.append("23");
	CML.append("24");CML.append("25");CML.append("26");

    CML1.append("1..5"); CML1.append("1..10"); CML1.append("1..15");
    CML1.append("1..20"); CML1.append("1..25");CML1.append("1..50");CML1.append("1..100");
    list<string> choice_option;
    choice_option.append("User define with matrix dimensions and values");
    choice_option.append("User define with matrix dimensions only");
    choice_option.append("Random");
 
	w1.init(-100,+100,-100);
   int c=3;
   w1.choice_item("",c,choice_option,choice_handler);
   w1.string_item("Quantity",quantityDefault,CML,8,quantity_handler);
   w1.string_item("Dimension",dimensionDefault,CML1,9,dimesion_handler);
   w1.string_item("Matrix Input",matrixinput);
   w1.set_item_width(900);
   w1.button("Compute", 50, but_action);
    w1.button("Reset", 10, reset_handler);
   w1.text_item("");
   w1.string_item("Sequence Of Dimensions",sequenceOfDimensions);
   w1.string_item("Optimal Parenthesization",optimalParenthesization);
   w1.string_item("Left To Right Scalar Multiplication",normalCost);
   w1.string_item("Optimized Scalar Multiplication",optimizeCost);
   w1.display(window::center,window::center);
   w1.disable_item(w1.get_item("Quantity"));
   w1.disable_item(w1.get_item("Dimension"));
   w1.disable_item(w1.get_item("Compute"));
   w1.disable_item(w1.get_item("Reset"));
   w1.draw_hline(0); 
   w1.draw_vline(0);

   double  x,y;
   point   p;
   window* w;

  // w1.read_mouse();
   while(read_mouse(w,x,y) != MOUSE_BUTTON(3))  
   { 
     if (w == &w1) // draw points
     {
		 put_back_event();
          w1 >> p;
         continue;
      }
	
    }

   return 0;
}
